// RMSThread.h: interface for the CRMSThread class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_RMSTHREAD_H__0B65F3A0_2492_4F6D_AA49_16E380984B1B__INCLUDED_)
#define AFX_RMSTHREAD_H__0B65F3A0_2492_4F6D_AA49_16E380984B1B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

//#define TRACE_SOCK		0

#define DEFAULT_TERMINATION_TIMEOUT		5000		// 2 seconds pause

class CRMSThread  
{
	friend DWORD WINAPI ThreadProc(LPVOID lpParameter);

public:
	HANDLE m_hThread;
	CRMSThread();
	virtual ~CRMSThread();

	virtual DWORD Terminate(BOOL bCritical = FALSE);
	virtual DWORD OnTerminate();
	virtual void OnCriticalTerminate();
	BOOL Execute();
	
	DWORD m_dwID;

protected:
	BOOL m_bQuit;		 // quit command
	BOOL m_bTerminated;  // terminated flag, should be set on exit
	DWORD m_result;
	DWORD MAGIC_H;

	HANDLE m_stopEvent;

	virtual DWORD ThreadFunc()=NULL;

	int recvtimeout(int s, char *buf, int len, int timeout)
	{
		fd_set fds;
		int n;
		struct timeval tv;

		// set up the file descriptor set
		FD_ZERO(&fds);
		FD_SET(s, &fds);

		// set up the struct timeval for the timeout
		tv.tv_sec = timeout;
		tv.tv_usec = 0;

		// wait until timeout or data received
		n = select(s+1, &fds, NULL, NULL, &tv);
		if (n == 0) return -2; // timeout!
		if (n == -1) return -1; // error

		// data must be here, so do a normal recv()
		return recv(s, buf, len, 0);
	}

#if defined(_DEBUG) && defined(TRACE_SOCK)

#ifndef DSIZE
#define DSIZE sizeof(DWORD)
#endif //ndef DSIZE
#ifndef BSIZE
#define BSIZE 20 * DSIZE
#endif //ndef BSIZE

	void pretrace( char* txt )
	{
		TRACE2("%x: %s", this, txt);
	}
	void trace( char FAR* buf, int len, int n )
	{
		TRACE1("(%04x)", n);
		if( (n != 0) && (n != SOCKET_ERROR) )
		{
			int i, j, k, l;
			l = (n < BSIZE) ? n : BSIZE;
			j = (n % DSIZE) ? n + DSIZE : n;
			j = (j / DSIZE) * DSIZE;
			j = (j < BSIZE) ? j : BSIZE;
			char data[BSIZE + DSIZE];
			memcpy(data, buf, l);
			k = j / DSIZE;
			for( i = 0; i < k; i++ )
			{
				TRACE1(" %08x", ((DWORD*)data)[i]);
			}
			TRACE0(" (");
			for( i = 0; i < l; i++ )
			{
				TRACE1("%c", data[i]);
			}
			TRACE0(")\n");
		}
		else
		{
			TRACE0("\n");
		}
	}

	int send( SOCKET s, const char FAR* buf, int len, int flags )
	{
		pretrace("send");
		int n = ::send(s, buf, len, flags);
		trace((char FAR*)buf, len, n);
		return n;
	}

	int recv( SOCKET s, char FAR* buf, int len, int flags )
	{
		pretrace("recv");
		int n = ::recv(s, buf, len, flags);
		trace(buf, len, n);
		return n;
	}

	int sendto( SOCKET s,
				const char FAR * buf,
				int len,
				int flags,
				const struct sockaddr FAR * to,
				int tolen )
	{
		pretrace("sendto");
		int n = ::sendto(s, buf, len, flags, to, tolen);
		trace((char FAR*)buf, len, n);
		return n;
	}

	int recvfrom( SOCKET s,
				  char FAR * buf,
				  int len,
				  int flags,
				  struct sockaddr FAR * from,
				  int FAR* fromlen )
	{
		pretrace("recvfrom");
		int n = ::recvfrom(s, buf, len, flags, from, fromlen);
		trace(buf, len, n);
		return n;
	}

#endif //defined(_DEBUG) && defined(TRACE_SOCK)

};

#endif // !defined(AFX_RMSTHREAD_H__0B65F3A0_2492_4F6D_AA49_16E380984B1B__INCLUDED_)
